home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / mplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  68.9 KB  |  2,505 lines  |  [TEXT/KAHL]

  1. /* Implementation of the "mplayer" AI in Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. #include "mplay.h"
  12.  
  13. #define unit_theater(unit) ((Theater *) (unit)->aihook)
  14.  
  15. #define set_unit_theater(unit,theater) ((unit)->aihook = (char *) (theater))
  16.  
  17. #define can_see_actual_units(side, x, y) (g_see_all() || cover((side), (x), (y)) > 0)
  18.  
  19. static int compare_weights PROTO ((const void *w1, const void *w2));
  20.  
  21. /* Flag to detect when shared mplayer init has been done. */
  22.  
  23. static int mplayerinited = FALSE;
  24.  
  25. void
  26. mplayer_init(side)
  27. Side *side;
  28. {
  29.     Unit *unit;
  30.  
  31.     /* (should do this only when absolutely needed - mplayer might
  32.        never actually be used) */
  33.     if (!mplayerinited) {
  34.     mplayer_init_shared();
  35.     mplayerinited = TRUE;
  36.     Dprintf("One mplayer AI is %d bytes.\n", sizeof(Strategy));
  37.     }
  38.     /* Make sure a strategy object exists. */
  39.     if (mplayer(side) == NULL)
  40.       create_strategy(side);
  41.     /* If the side has no units at the moment, it doesn't really need to
  42.        plan. */
  43.     if (!side_has_units(side))
  44.       return;
  45.     analyze_the_game(side);
  46.     /* Reset plans of any units that were not doing anything. */
  47.     for_all_side_units(side, unit) {
  48.         if (in_play(unit) && unit->plan && unit->plan->aicontrol) {
  49.         unit->plan->asleep = FALSE;
  50.         unit->plan->reserve = FALSE;
  51.         /* We might want to mess with the unit now, so clear all
  52.            delays. */
  53.         unit->plan->delayed = FALSE;
  54.         unit->plan->waitingfortasks = FALSE;
  55.         if (unit->plan->type == PLAN_PASSIVE) {
  56.         unit->plan->type = PLAN_NONE;
  57.         }
  58.         }
  59.     }
  60. }
  61.  
  62. /* At the beginning of each turn, make plans and review the situation. */
  63.  
  64. void
  65. mplayer_init_turn(side)
  66. Side *side;
  67. {
  68.     /* Cases where we no longer need to run. */
  69.     if (!side->ingame)
  70.       return;
  71.     /* A side without units hasn't got anything to do but wait. */
  72.     /* (should account for possible units on controlled sides) */
  73.     if (!side_has_units(side))
  74.       return;
  75.     /* Mplayers in a hacked game will not play,
  76.        unless they're being debugged. */
  77.     if (compromised && !DebugM)
  78.       return;
  79.     update_all_progress_displays("ai turn init start", side->id);
  80.     DMprintf("%s mplayer init turn\n", side_desig(side));
  81.     /* Make sure a strategy object exists. */
  82.     if (mplayer(side) == NULL)
  83.       create_strategy(side);
  84.     /* Look over the game design we're playing with. */
  85.     analyze_the_game(side);
  86.     /* If this game is one that can be won, as opposed to
  87.        just dinking around, figure how to win it. */
  88.     if (mplayer(side)->trytowin) {
  89.     /* Check out the current goal tree first. */
  90.     review_goals(side);
  91.     /* Goal analysis might have triggered resignation. */
  92.     if (!side->ingame)
  93.       goto done;
  94.     /* Check out all the theaters. */
  95.     review_theaters(side);
  96.     /* Check out all of our units. */
  97.     review_units(side);
  98.     /* Decide on the new current plan. */
  99.     update_side_strategy(side);
  100.     /* Propagate this to individual unit plans. */
  101.     update_unit_plans(side);
  102.     } else {
  103.     update_unit_plans_randomly(side);
  104.     }
  105.   done:
  106.     update_all_progress_displays("", side->id);
  107.     DMprintf("%s mplayer init turn done\n", side_desig(side));
  108. }
  109.  
  110. /* Create and install an entirely new strategy object for the side. */
  111.  
  112. void
  113. create_strategy(side)
  114. Side *side;
  115. {
  116.     Strategy *strategy = (Strategy *) xmalloc(sizeof(Strategy));
  117.  
  118.     /* Put the specific structure into a generic slot. */
  119.     side->ai = (struct a_ai *) strategy;
  120.     strategy->type = mplayertype;
  121.     /* Allocate a table of pointers to theaters, for access via small numbers
  122.        rather than full pointers. */
  123.     strategy->theatertable = (Theater **) xmalloc(127 * sizeof(Theater *));
  124.     /* Allocate a layer of indexes into the theater table. */
  125.     strategy->areatheaters = malloc_area_layer(char);
  126.     /* Allocate random things. */
  127.     /* Arrays for unit types. */
  128.     strategy->actualmix = (short *) xmalloc(numutypes * sizeof(short));
  129.     strategy->expectedmix = (short *) xmalloc(numutypes * sizeof(short));
  130.     strategy->idealmix = (short *) xmalloc(numutypes * sizeof(short));
  131.     /* Arrays for terrain types. */
  132.     strategy->terrainguess = (short *) xmalloc(numttypes * sizeof(short));
  133.     /* Set everything to correct initial values. */
  134.     reset_strategy(side);
  135. }
  136.  
  137. /* Put all the right initial values into the strategy, but don't allocate anything. */
  138.  
  139. void
  140. reset_strategy(side)
  141. Side *side;
  142. {
  143.     int u, t, dir;
  144.     Strategy *strategy = (Strategy *) side->ai;
  145.  
  146.     /* Remember when we did this. */
  147.     strategy->creationdate = g_turn();
  148.     /* Null out various stuff. */
  149.     strategy->numgoals = 0;
  150.     strategy->theaters = NULL;
  151.     /* Actually we start with no theaters, but it's convenient to leave entry 0
  152.        in the theater table pointing to NULL. */
  153.     strategy->numtheaters = 1;
  154.     /* Clear pointers to special-purpose theaters. */
  155.     strategy->homefront = NULL;
  156.     for_all_directions(dir) {
  157.         strategy->perimeters[dir] = strategy->midranges[dir] = strategy->remotes[dir] = NULL;
  158.     }
  159.     strategy->explorersneeded = 0;
  160.     /* Reset the summation of our exploration needs. */
  161.     for_all_unit_types(u) {
  162.     strategy->actualmix[u] = 0;
  163.     strategy->expectedmix[u] = 0;
  164.     strategy->idealmix[u] = 0;
  165.     }
  166.     for_all_terrain_types(t) {
  167.     strategy->terrainguess[t] = 0;
  168.     }
  169.     strategy->analyzegame = TRUE;
  170.     /* Analyze the game and decide our basic goals. */
  171.     analyze_the_game(side);
  172. }
  173.  
  174. /* Look over the game design and decide what we're supposed to be doing,
  175.    if anything at all.  This just sets up toplevel goals based on the
  176.    game design, does not evaluate goals or any such. */
  177.  
  178. void
  179. analyze_the_game(side)
  180. Side *side;
  181. {
  182.     int maybedraw;
  183.     Goal *goal;
  184.  
  185.     if (mplayer(side)->analyzegame) {
  186.     if (should_try_to_win(side)) {
  187.         mplayer(side)->trytowin = TRUE;
  188.         /* This is our whole purpose in the game. */
  189.         goal = create_goal(GOAL_WON_GAME, side, TRUE);
  190.         add_goal(side, goal);
  191.         /* Now figure what exactly we have to do in order to win. */
  192.         determine_subgoals(side);
  193.         /* Machine will want to keep playing as long as it thinks
  194.            it has a chance to win. */
  195.         maybedraw = FALSE;
  196.     } else {
  197.         mplayer(side)->trytowin = FALSE;
  198.         /* Since the side is not trying to win anything, it will be
  199.            pretty laidback about whether to keep the game going. */
  200.         maybedraw = TRUE;
  201.     }
  202.     /* Be trusting about game saves, at least for now. */
  203.     set_willing_to_save(side, TRUE);
  204.     set_willing_to_draw(side, maybedraw);
  205.     mplayer(side)->analyzegame = FALSE;
  206.     DMprintf("%s will try to %s this game\n",
  207.          side_desig(side),
  208.          mplayer(side)->trytowin ? "win" : "have fun in");
  209.     /* (should summarize any per-side goals here) */
  210.     }
  211. }
  212.  
  213. void
  214. determine_subgoals(side)
  215. Side *side;
  216. {
  217.     Side *side2;
  218.     Scorekeeper *sk;
  219.     Goal *goal;
  220.  
  221.     /* Look at each scorekeeper and decide on appropriate goals. */
  222.     for_all_scorekeepers(sk) {
  223.         if (match_keyword(sk->body, K_LAST_SIDE_WINS)) {
  224.         /* We want to "kick butt" - *everybody* else's butt. */
  225.         for_all_sides(side2) {
  226.         if (!trusted_side(side, side2) && side2->ingame) {
  227.             goal = create_goal(GOAL_WON_GAME, side2, FALSE);
  228.             add_goal(side, goal);
  229.             /* (should add "search-and-destroy" as corollaries) */
  230.             /* (should add protection of own valuable units) */
  231.         }
  232.         }
  233.         } else {
  234.         DMprintf("Don't understand a scorekeeper!");
  235.         }
  236.     }
  237.     /* We might develop a sudden interest in exploration. */
  238.     /* (but should only be if information is really important to winning) */
  239.     if (!g_see_all()) {
  240.     if (!g_terrain_seen()) {
  241.         add_goal(side, create_goal(GOAL_WORLD_KNOWN, side, TRUE));
  242.     }
  243.     /* It will be important to keep track of other sides' units
  244.        as much as possible. */
  245.     for_all_sides(side2) {
  246.         if (side != side2) {
  247.         goal = create_goal(GOAL_POSITIONS_KNOWN, side, TRUE);
  248.         goal->args[0] = (long) side2;
  249.         add_goal(side, goal);
  250.         }
  251.     }
  252.     /* Also add the general goal of knowing where indeps are. */
  253.     goal = create_goal(GOAL_POSITIONS_KNOWN, side, TRUE);
  254.     goal->args[0] = (long) NULL;
  255.     add_goal(side, goal);
  256.     }
  257. }
  258.  
  259. /* Do a combination of analyzing existing theaters and creating new ones. */
  260.  
  261. void
  262. review_theaters(side)
  263. Side *side;
  264. {
  265.     int x, y, u, s, pop, totnumunits;
  266.     int firstcontact = FALSE;
  267.     int homefound = FALSE;
  268.     short view;
  269.     Unit *unit;
  270.     Side *firstcontactside, *homefoundside, *otherside;
  271.     Theater *theater;
  272.  
  273.     /* Create some theaters if none exist. */
  274.     if (mplayer(side)->theaters == NULL) {
  275.     create_initial_theaters(side);
  276.     }
  277.     for_all_theaters(side, theater) {
  278.     theater->allied_units = 0;
  279.     theater->makers = 0;
  280.     theater->unexplored = 0;
  281.     theater->border = FALSE;
  282.     theater->allied_bases = 0;
  283.     for_all_unit_types(u) {
  284.         theater->numassigned[u] = 0;
  285.         theater->numneeded[u] = 0;
  286.         theater->numenemies[u] = 0;
  287.         theater->numsuspected[u] = theater->numsuspectedmax[u] = 0;
  288.         theater->numtotransport[u] = 0;
  289.     }
  290.     if (people_sides_defined()) {
  291.         for (s = 0; s <= numsides; ++s) theater->people[s] = 0;
  292.     }
  293. /*    theater->enemy_strength /= 2; */
  294.     theater->units_lost /= 2;
  295.     theater->size = 0;
  296.     theater->xmin = theater->ymin = -1;
  297.     theater->xmax = theater->ymax = -1;
  298.     }
  299.     /* Now look at all the units that we can. */
  300.     for_all_side_units(side, unit) {
  301.         if (in_play(unit)) {
  302.         theater = unit_theater(unit);
  303.         if (theater != NULL) {
  304.         ++(theater->allied_units);
  305.         (theater->numassigned[unit->type])++;
  306.         if (isbase(unit)) theater->allied_bases++;
  307.         }
  308.     }
  309.     }
  310.     /* (should also analyze allies etc) */
  311.     /* Now look at the whole world. */
  312.     for_all_interior_cells(x, y) {
  313.     if ((theater = theater_at(side, x, y)) != NULL) {
  314.         ++(theater->size);
  315.         if (theater->xmin < 0 || x < theater->xmin) theater->xmin = x;
  316.         if (theater->ymin < 0 || y < theater->ymin) theater->ymin = y;
  317.         if (theater->xmax < 0 || x > theater->xmax) theater->xmax = x;
  318.         if (theater->ymax < 0 || y > theater->ymax) theater->ymax = y;
  319.         if (g_see_all() || cover(side, x, y) > 0) {
  320.             for_all_stack(x, y, unit) {
  321.                 /* what about occupants? */
  322.                 if (in_play(unit)
  323.                     && side != unit->side
  324.                     && (unit->side != NULL
  325.                         || u_point_value(unit->type) > 0)) {
  326.             if (enemy_side(side, unit->side))
  327.               ++(theater->numenemies[unit->type]);
  328.                     if (mplayer(side)->contacted[side_number(unit->side)] == 0) {
  329.                 mplayer(side)->contacted[side_number(unit->side)] = 1;
  330.                 if (unit->side != NULL) {
  331.                 firstcontact = TRUE;
  332.                 firstcontactside = unit->side;
  333.                 }
  334.                     }
  335.                     if (mplayer(side)->homefound[side_number(unit->side)] == 0
  336.                         && !mobile(unit->type)) {
  337.                 mplayer(side)->homefound[side_number(unit->side)] = 1;
  338.                 if (unit->side != NULL) {
  339.                 homefound = TRUE;
  340.                 homefoundside = unit->side;
  341.                 }
  342.                     }
  343.                 }
  344.             }
  345.         if (people_sides_defined()) {
  346.             if ((pop = people_side_at(x, y)) != NOBODY) {
  347.             ++(theater->people[pop]);
  348.                     if (mplayer(side)->homefound[pop] == 0) {
  349.                 mplayer(side)->homefound[pop] = 1;
  350.                 if (pop != 0) {
  351.                 homefound = TRUE;
  352.                 homefoundside = side_n(pop);
  353.                 }
  354.                     }
  355.             }
  356.         }
  357.         } else {
  358.         if (terrain_view(side, x, y) == UNSEEN) {
  359.             ++(theater->unexplored);
  360.         } else {
  361.             view = unit_view(side, x, y);
  362.             if (view != EMPTY) {
  363.             if (side != side_n(vside(view))
  364.                 && (vside(view) != 0
  365.                     /* (should count indep prizes separately) */
  366.                     || u_point_value(vtype(view)) > 0)) {
  367.                 u = vtype(view);
  368.                 if (enemy_side(side, side_n(vside(view)))) {
  369.                 ++(theater->numsuspected[u]);
  370.                 ++(theater->numsuspectedmax[u]);
  371.                 }
  372.             }
  373.             }
  374.             if (people_sides_defined()) {
  375.             pop = people_side_at(x, y);
  376.             if (pop != NOBODY) {
  377.                 ++(theater->people[pop]);
  378.             }
  379.             }
  380.         }
  381.         }
  382.     }
  383.     }
  384.     for_all_theaters(side, theater) {
  385.         theater->x = (theater->xmin + theater->xmax) / 2;
  386.         theater->y = (theater->ymin + theater->ymax) / 2;
  387.         theater->enemystrengthmin = theater->enemystrengthmax = 0;
  388.         for_all_unit_types(u) {
  389.         theater->enemystrengthmin +=
  390.           theater->numenemies[u] + theater->numsuspected[u];
  391.     }
  392.     theater->enemystrengthmax = theater->enemystrengthmin;
  393.     }
  394.     if (firstcontact || homefound) {
  395.         for_all_side_units(side, unit) {
  396.         if (unit->plan && unit->plan->aicontrol) {
  397.         unit->plan->maingoal = NULL;
  398.         unit->plan->formation = NULL;
  399.         unit->plan->funit = NULL;
  400.         /* Force a replan. */
  401.         unit->plan->type = PLAN_NONE;
  402.         unit->plan->asleep = FALSE;
  403.         unit->plan->reserve = FALSE;
  404.         unit->plan->waitingfortasks = FALSE;
  405.         set_unit_theater(unit, NULL);
  406.         update_unit_display(side, unit, TRUE);
  407.         }
  408.     }
  409.     }
  410.     for_all_theaters(side, theater) {
  411.     DMprintf("%s theater \"%s\" at %d,%d from %d,%d to %d,%d (size %d)\n",
  412.          side_desig(side), theater->name, theater->x, theater->y,
  413.          theater->xmin, theater->ymin, theater->xmax, theater->ymax,
  414.          theater->size);
  415.     /* Summarize what we know about the theater. */
  416.     DMprintf("%s theater \"%s\"", side_desig(side), theater->name);
  417.     if (!g_see_all() && theater->unexplored > 0) {
  418.         DMprintf(" unexplored %d", theater->unexplored);
  419.     }
  420.     DMprintf(" enemy %d", theater->enemystrengthmin);
  421.     if (theater->enemystrengthmin != theater->enemystrengthmax) {
  422.         DMprintf("-%d", theater->enemystrengthmax);
  423.     }
  424.     for_all_unit_types(u) {
  425.         if (theater->numenemies[u] + theater->numsuspected[u] > 0) {
  426.             DMprintf(" %3s %d", u_type_name(u), theater->numenemies[u]);
  427.             if (theater->numsuspected[u] > 0) {
  428.             DMprintf("+%d", theater->numsuspected[u]);
  429.         }
  430.         }
  431.     }
  432.     if (people_sides_defined()) {
  433.         DMprintf(" people");
  434.         for (s = 0; s <= numsides; ++s) {
  435.         if (theater->people[s] > 0) {
  436.             DMprintf(" s%d %d", s, theater->people[s]);
  437.         }
  438.         }
  439.     }
  440.     DMprintf("\n");
  441.     totnumunits = 0;
  442.     for_all_unit_types(u) {
  443.         totnumunits +=
  444.           (theater->numassigned[u] + theater->numneeded[u] + theater->numtotransport[u]);
  445.     }
  446.     if (totnumunits > 0) {
  447.         /* Summarize the status of our own units in this theater. */
  448.         DMprintf("%s theater \"%s\" has ", side_desig(side), theater->name);
  449.         for_all_unit_types(u) {
  450.         if (theater->numassigned[u] + theater->numneeded[u] + theater->numtotransport[u] > 0) {
  451.             DMprintf(" %d %3s", theater->numassigned[u], u_type_name(u));
  452.             if (theater->numneeded[u] > 0) {
  453.                 DMprintf(" (of %d needed)", theater->numneeded[u]);
  454.             }
  455.             if (theater->numtotransport[u] > 0) {
  456.                 DMprintf(" (%d awaiting transport)", theater->numtotransport[u]);
  457.             }
  458.         }
  459.         }
  460.         DMprintf("\n");
  461.     }
  462.     }
  463.     /* Also summarize contacts. */
  464.     for_all_sides(otherside) {
  465.         if (otherside != side) {
  466.         if (mplayer(side)->contacted[otherside->id]) {
  467.         DMprintf("%s contacted s%d", side_desig(side), otherside->id);
  468.         if (mplayer(side)->homefound[otherside->id]) {
  469.             DMprintf(", home found");
  470.         }
  471.         DMprintf("\n");
  472.         }
  473.         }
  474.     }
  475. }
  476.  
  477. Theater *tmptheater;
  478.  
  479. int
  480. fn_set_theater(x, y)
  481. int x, y;
  482. {
  483.     set_theater_at(tmpside, x, y, tmptheater);
  484.     return 0;
  485. }
  486.  
  487. /* Set up the initial set of theaters. */
  488.  
  489. void
  490. create_initial_theaters(side)
  491. Side *side;
  492. {
  493.     int x, y, dir, dist, i, j;
  494.     int xmin, ymin, xmax, ymax;
  495.     int homeradius, perimradius, midradius, xxx;
  496.     int numthx, numthy, thwid, thhgt;
  497.     Unit *unit;
  498.     Theater *homefront, *enemyarea, *theater;
  499.     Theater *gridtheaters[8][8];
  500.     Strategy *strategy = mplayer(side);
  501.  
  502.     for (i = 0; i < 8; ++i) {
  503.     for (j = 0; j < 8; ++j) {
  504.         gridtheaters[i][j] = NULL;
  505.     }
  506.     }
  507.     /* Compute bbox of initial (should also do enemy?) units. */
  508.     xmin = area.width;  ymin = area.height;  xmax = ymax = 0;
  509.     for_all_side_units(side, unit) {
  510.     if (alive(unit) /* and other preconditions? */) {
  511.         if (unit->x < xmin) xmin = unit->x;
  512.         if (unit->y < ymin) ymin = unit->y;
  513.         if (unit->x > xmax) xmax = unit->x;
  514.         if (unit->y > ymax) ymax = unit->y;
  515.     }
  516.     }
  517.     /* Most games start with each side's units grouped closely together.
  518.        If this is not the case, do something else. */
  519.     if (xmax - xmin > area.width / 4 && ymax - ymin > area.height / 4) {
  520.     /* (should do some sort of clustering of units) */
  521.     if (0 /*people_sides_defined()*/) {
  522.         homefront = create_theater(side);
  523.         homefront->name = "Home Front";
  524.         enemyarea = create_theater(side);
  525.         enemyarea->name = "Enemy Area";
  526.         for_all_interior_cells(x, y) {
  527.             if (people_side_at(x, y) == side->id) {
  528.             set_theater_at(side, x, y, homefront);
  529.             } else {
  530.             set_theater_at(side, x, y, enemyarea);
  531.             }
  532.         }
  533.     } else {
  534.         /* Divide the world up along a grid. */
  535.         numthx = (area.width  > 60 ? (area.width  > 120 ? 7 : 5) : 3);
  536.         numthy = (area.height > 60 ? (area.height > 120 ? 7 : 5) : 3);
  537.         thwid = max(8, area.width / numthx);
  538.         thhgt = max(8, area.height / numthy);
  539.             for_all_interior_cells(x, y) {
  540.             i = x / thwid;  j = y / thhgt;
  541.             if (gridtheaters[i][j] == NULL) {
  542.                 theater = create_theater(side);
  543.                 sprintf(spbuf, "Grid %d,%d", i, j);
  544.                 theater->name = copy_string(spbuf);
  545.                 theater->x = x;  theater->y = y;
  546.                 gridtheaters[i][j] = theater;
  547.             } else {
  548.                 theater = gridtheaters[i][j];
  549.             }
  550.             set_theater_at(side, x, y, theater);
  551.         }
  552.     }
  553.     return;
  554.     } else {
  555.     /* Always create a first theater that covers the starting area. */
  556.     homefront = create_theater(side);
  557.     homefront->name = "Home Front";
  558.     /* Calculate startxy if not already available. */
  559.     if (side->startx < 0 && side->starty < 0)
  560.       calc_start_xy(side);
  561.     homefront->x = side->startx;  homefront->y = side->starty;
  562.     strategy->homefront = homefront;
  563.     homeradius = max(5, g_min_radius());
  564.     perimradius = max(homeradius + 5, g_min_separation() - homeradius);
  565.     midradius = max(perimradius + 10, g_min_separation() * 2);
  566.     xxx = max((side->startx - perimradius), (area.width - side->startx - perimradius));
  567.     xxx /= 2;
  568.     midradius = min(midradius, perimradius + xxx);
  569.     for_all_interior_cells(x, y) {
  570.         if (people_sides_defined()
  571.         && people_side_at(x, y) == side->id) {
  572.         set_theater_at(side, x, y, homefront);
  573.         } else {
  574.         dist = distance(x, y, side->startx, side->starty);
  575.         if (dist < homeradius) {
  576.             set_theater_at(side, x, y, homefront);
  577.         } else {
  578.             dir = approx_dir(x - side->startx, y - side->starty);
  579.             if (dist < perimradius) {
  580.             if (strategy->perimeters[dir] == NULL) {
  581.                 theater = create_theater(side);
  582.                 sprintf(spbuf, "Perimeter %s", dirnames[dir]);
  583.                 theater->name = copy_string(spbuf);
  584.                 theater->x = x;  theater->y = y;
  585.                 strategy->perimeters[dir] = theater;
  586.             } else {
  587.                 theater = strategy->perimeters[dir];
  588.             }
  589.             } else if (dist < midradius) {
  590.             if (strategy->midranges[dir] == NULL) {
  591.                 theater = create_theater(side);
  592.                 sprintf(spbuf, "Midrange %s", dirnames[dir]);
  593.                 theater->name = copy_string(spbuf);
  594.                 theater->x = x;  theater->y = y;
  595.                 strategy->midranges[dir] = theater;
  596.             } else {
  597.                 theater = strategy->midranges[dir];
  598.             }
  599.             } else {
  600.             if (strategy->remotes[dir] == NULL) {
  601.                 theater = create_theater(side);
  602.                 sprintf(spbuf, "Remote %s", dirnames[dir]);
  603.                 theater->name = copy_string(spbuf);
  604.                 theater->x = x;  theater->y = y;
  605.                 strategy->remotes[dir] = theater;
  606.             } else {
  607.                 theater = strategy->remotes[dir];
  608.             }
  609.             }
  610.             set_theater_at(side, x, y, theater);
  611.             }
  612.         }
  613.     }  
  614.     }
  615.     /* Assign all units to the theater they're currently in. */
  616.     /* (how do reinforcements get handled? mplayer should get hold of perhaps) */
  617.     for_all_side_units(side, unit) {
  618.     if (in_play(unit) /* and other preconditions? */) {
  619.         set_unit_theater(unit, theater_at(side, unit->x, unit->y));
  620.     }
  621.     }
  622. }
  623.  
  624. /* Create a single theater object and link it into the list of
  625.    theaters. */
  626.  
  627. /* (should be able to re-use theaters in already in theater table) */
  628.  
  629. Theater *
  630. create_theater(side)
  631. Side *side;
  632. {
  633.     Theater *theater = (Theater *) xmalloc(sizeof(Theater));
  634.  
  635.     if (mplayer(side)->numtheaters > MAXTHEATERS) return NULL;
  636.     theater->id = (mplayer(side)->numtheaters)++;
  637.     theater->name = "?";
  638.     theater->maingoal = NULL;
  639.     theater->people = (long *) xmalloc ((numsides + 1) * sizeof(long));
  640.     /* (should alloc other array slots too) */
  641.     /* Connect theater into a linked list. */
  642.     theater->next = mplayer(side)->theaters;
  643.     mplayer(side)->theaters = theater;
  644.     /* Install it into the theater table also. */
  645.     mplayer(side)->theatertable[theater->id] = theater;
  646.     return theater;
  647. }
  648.  
  649. /* Examine the goals to see what has been accomplished and what still needs
  650.    to be done. */
  651.  
  652. void
  653. review_goals(side)
  654. Side *side;
  655. {
  656.     int i;
  657.     Scorekeeper *sk;
  658.     Goal *goal;
  659.     Strategy *strategy = mplayer(side);
  660.  
  661.     for (i = 0; i < strategy->numgoals; ++i) {
  662.     goal = strategy->goals[i];
  663.     DMprintf("%s has %s\n", side_desig(side), goal_desig(goal));
  664.     }
  665.     /* Should look at certainty of each goal and decide whether to keep or
  666.        drop it, and mention in debug output also. */
  667.     /* Also think about resigning. */
  668.     if (keeping_score()) {
  669.     for_all_scorekeepers(sk) {
  670.         if (symbolp(sk->body)
  671.         && match_keyword(sk->body, K_LAST_SIDE_WINS)) {
  672.         decide_resignation(side);
  673.         }
  674.     }
  675.     }
  676. }
  677.  
  678.  
  679. /* Sometimes there is no point in going on, but be careful not to be too
  680.    pessimistic.  Right now we only give up if no hope at all. */
  681.  
  682. void
  683. decide_resignation(side)
  684. Side *side;
  685. {
  686.     int u, couldwin = TRUE, coulddraw = TRUE, chance = 0;
  687.     int sn1, x, y, uview;
  688.     Side *side1, *side2;
  689.     Strategy *strategy = mplayer(side);
  690.     Unit *unit;
  691.  
  692.     for_all_sides(side1) {
  693.     sn1 = side_number(side1);
  694.     for_all_unit_types(u) {
  695.         strategy->strengths[sn1][u] = 0;
  696.     }
  697.     if (side1 == side || allied_side(side, side1)) {
  698.         for_all_side_units(side1, unit) {
  699.         if (in_play(unit)) {  /* but what about reinforcements? */
  700.             ++(strategy->strengths[sn1][unit->type]);
  701.         }
  702.         }
  703.     }
  704.     }
  705.     if (g_see_all()) {
  706.         for_all_cells(x, y) {
  707.         for_all_stack(x, y, unit) {
  708.             side2 = unit->side;
  709.             if (side2 != NULL && enemy_side(side, side2)) {
  710.             ++(strategy->strengths[side2->id][unit->type]);
  711.             }
  712.         }
  713.         }
  714.     } else {
  715.         /* Look at the current view to get enemy strength. */
  716.         /* This is too easily faked, and doesn't know about hiding units... */
  717.         /* Should also discount old data. */
  718.         for_all_cells(x, y) {
  719.         uview = unit_view(side, x, y);
  720.         if (uview != UNSEEN && uview != EMPTY) {
  721.             side2 = side_n(vside(uview));
  722.             if (side2 != NULL && enemy_side(side, side2)) {
  723.             ++(strategy->strengths[side2->id][vtype(uview)]);
  724.             }
  725.         }
  726.         }
  727.     }
  728.     /* Estimate point values. */
  729.     for_all_sides(side1) {
  730.     sn1 = side1->id;
  731.     strategy->points[sn1] = 0;
  732.     for_all_unit_types(u) {
  733.         strategy->points[sn1] += strategy->strengths[sn1][u] * u_point_value(u);
  734.     }
  735.     }
  736.     /* Estimate point values, and how many units of each type in allied group. */
  737.     for_all_sides(side1) {
  738.     sn1 = side1->id;
  739.     for_all_unit_types(u) {
  740.         strategy->alstrengths[sn1][u] = strategy->strengths[sn1][u];
  741.         for_all_sides(side2) {
  742.         if (side1 != side2 && allied_side(side1, side2)) {
  743.             strategy->alstrengths[sn1][u] +=
  744.               strategy->strengths[side2->id][u];
  745.         }
  746.         }
  747.     }
  748.     for_all_sides(side2) {
  749.         if (side1 != side2 && allied_side(side1, side2)) {
  750.             strategy->alpoints[sn1] += strategy->points[side2->id];
  751.         }
  752.     }
  753.     }
  754.     /* Dump out a detailed listing of our estimates. */
  755.     if (DebugM) {
  756.     for_all_sides(side1) {
  757.         DMprintf("%s strength estimate: ", side_desig(side1));
  758.         for_all_unit_types(u) {
  759.         DMprintf(" %d", strategy->strengths[side1->id][u]);
  760.         }
  761.         DMprintf("\n");
  762.     }
  763.     }
  764.     for_all_sides(side1) {
  765.       if (side != side1 && !allied_side(side, side1)) {
  766.     sn1 = side1->id;
  767.     if (strategy->points[sn1] > 5 * strategy->points[side->id]) {
  768.         chance = 50;
  769.     }
  770.     if (strategy->points[sn1] > 8 * strategy->points[side->id]) {
  771.         chance = 90;
  772.     }
  773.       }
  774.     }
  775.     /* Whether or not we actually resign, we may be willing to
  776.        go for a draw if other players want to. */
  777.     /* (Note that toggling this flag is not exactly poker-faced
  778.        behavior, but I doubt human players will be able to derive
  779.        much advantage, since they'll already have a pretty good
  780.        idea if the AI is in trouble or not.) */
  781.     set_willing_to_draw(side, (chance > 0));
  782.     /* Maybe resign. */
  783.     if (chance > 0) {
  784.     if (probability(chance)) {
  785.         give_up(side);
  786.     }
  787.     }
  788. }
  789.  
  790. /* If a machine player resigns, it tries to help its friends. */
  791.  
  792. void
  793. give_up(side)
  794. Side *side;
  795. {
  796.     Side *side1;
  797.  
  798.     /* (should have to give units to controlling side if there is one) */
  799.     /* Try to give away all of our units to an ally. */
  800.     for_all_sides(side1) {
  801.     if (side != side1 && allied_side(side, side1)) {
  802.         resign_game(side, side1);
  803.         return;
  804.     }
  805.     }
  806.     /* (should give to any positively-regarded side?) */
  807.     /* No allies, let everything become independent. */
  808.     /* (should disband all units that can be disbanded?) */
  809.     resign_game(side, NULL);
  810. }
  811.  
  812. /* Go through all our units (and allied ones?). */
  813.  
  814. void
  815. review_units(side)
  816. Side *side;
  817. {
  818.     Unit *unit;
  819.     Plan *plan;
  820.     Theater *oldtheater, *theater;
  821.     
  822.     for_all_side_units(side, unit) {
  823.     if (in_play(unit) && unit->plan && unit->plan->aicontrol) {
  824.         plan = unit->plan;
  825.         oldtheater = unit_theater(unit);
  826.         /* Goal might have become satisfied. */
  827.         if (plan->maingoal) {
  828.         if (goal_truth(side, plan->maingoal) == 100) {
  829.             DMprintf("%s %s satisfied, removing\n",
  830.                  unit_desig(unit), goal_desig(plan->maingoal));
  831.             plan->maingoal = NULL;
  832.             /* Force a replan. */
  833.             plan->type = PLAN_NONE;
  834.             set_unit_theater(unit, NULL);
  835.         }
  836.         }
  837.         /* Theater might have become explored enough (90% known). */
  838.         if (plan->type == PLAN_EXPLORATORY
  839.             && (theater = unit_theater(unit)) != NULL
  840.             && theater->unexplored < theater->size / 10) {
  841.             DMprintf("%s theater %s is mostly known\n",
  842.                  unit_desig(unit), theater->name);
  843.             plan->maingoal = NULL;
  844.             /* Force a replan. */
  845.             plan->type = PLAN_NONE;
  846.             set_unit_theater(unit, NULL);
  847.         }
  848.         theater = unit_theater(unit);
  849.         DMprintf("%s currently assigned to %s",
  850.                  unit_desig(unit),
  851.              (theater ? theater->name : "no theater"));
  852.         if (oldtheater != theater) {
  853.             DMprintf(" (was %s)",
  854.              (oldtheater ? oldtheater->name : "no theater"));
  855.         }
  856.         DMprintf("\n");
  857.     }
  858.     }
  859.     /* Could notify display about unit plan mix? */
  860. }
  861.  
  862. /* Look at our current overall strategy and hack it as needed. */
  863.  
  864. void
  865. update_side_strategy(side)
  866. Side *side;
  867. {
  868.     Theater *theater;
  869.  
  870.     Dprintf("%s updating strategy\n", side_desig(side));
  871.     /* Add something to add/update theaters as things open up. (?) */
  872.     for_all_theaters(side, theater) {
  873.     decide_theater_needs(side, theater);
  874.     }
  875. }
  876.  
  877. /* Figure out how many units to request for each area. */
  878.  
  879. void
  880. decide_theater_needs(side, theater)
  881. Side *side;
  882. Theater *theater;
  883. {
  884.     if (theater->unexplored > 0) {
  885.         /* Exploration is less important when 90% of a theater is known. */
  886.         if (theater->unexplored > (theater->size / 10)) {
  887.         ++(mplayer(side)->explorersneeded);
  888.         }
  889.     /* Should look for good exploration units. */
  890.     theater->importance = 50;  /* should depend on context */
  891. /*    theater->reinforce = EXPLORE_AREA;  */
  892. #if 0
  893.     } else if (0 /* theater->enemy_strength < 5 */) {
  894.     if (theater->allied_makers == 0
  895.         && theater->makers > 0
  896.         && theater->nearby) {
  897.         theater->reinforce = GUARD_BORDER_TOWN + 2 * theater->makers;
  898.     } else if (theater->makers > 0) {
  899.         theater->reinforce = (theater->border ? GUARD_BORDER_TOWN :
  900.                   GUARD_TOWN) + 2 * theater->allied_makers;
  901.     } else if (theater->allied_bases > 0) {
  902.         theater->reinforce = (theater->border ? GUARD_BORDER: GUARD_BASE);
  903.     } else if (theater->border) {
  904.         theater->reinforce = NO_UNITS;
  905.     } else {
  906.         theater->reinforce = NO_UNITS;
  907.     }
  908.     } else {
  909.     if (theater->allied_makers > 0) {
  910.         theater->reinforce = DEFEND_TOWN + 5 * theater->makers;
  911.     } else if (theater->allied_bases > 0) {
  912.         theater->reinforce = DEFEND_BASE + theater->allied_bases;
  913.     } else {
  914.         theater->reinforce = 0 /* DEFEND_AREA */;
  915.     }
  916. #endif
  917.     }
  918. }
  919.  
  920. /* For each unit, decide what it should be doing (if anything).  This is
  921.    when a side takes the initiative;  a unit can also request info from
  922.    its side when it is working on its individual plan. */
  923.  
  924. void
  925. update_unit_plans(side)
  926. Side *side;
  927. {
  928.     Unit *unit;
  929.  
  930.     for_all_side_units(side, unit) {
  931.     if (is_active(unit) && unit->plan != NULL) {
  932.         mplayer_decide_plan(side, unit);
  933.     }
  934.     }
  935. }
  936.  
  937. /* Randomly change a unit's plans.  (This is really more for
  938.    debugging, exercising plan execution code in novel ways.) */
  939.  
  940. void
  941. update_unit_plans_randomly(side)
  942. Side *side;
  943. {
  944.     Unit *unit;
  945.  
  946.     for_all_side_units(side, unit) {
  947.     if (is_active(unit) && unit->plan && unit->plan->aicontrol) {
  948.         if (probability(10)) {
  949.         DMprintf("Randomly changed %s plan %s",
  950.              unit_desig(unit), plan_desig(unit->plan));
  951.         unit->plan->type = xrandom((int) NUMPLANTYPES);
  952.         DMprintf("to plan %s\n", plan_desig(unit->plan));
  953.         }
  954.         /* (should add/remove goals randomly) */
  955.         if (probability(10)) {
  956.         unit->plan->reserve = FALSE;
  957.         }
  958.         if (probability(10)) {
  959.         unit->plan->asleep = FALSE;
  960.         }
  961.     }
  962.     }
  963. }
  964.  
  965. /* Push a new goal onto the side's list of goals. */
  966.  
  967. /* (this should only add goals that are not already present) */
  968.  
  969. void
  970. add_goal(side, goal)
  971. Side *side;
  972. Goal *goal;
  973. {
  974.     if (mplayer(side)->numgoals < MAXGOALS) {
  975.     mplayer(side)->goals[(mplayer(side)->numgoals)++] = goal;
  976.     }
  977. }
  978.  
  979. Goal *
  980. has_goal(side, goaltype)
  981. Side *side;
  982. GoalType goaltype;
  983. {
  984.     int i;
  985.     Goal *goal;
  986.  
  987.     for (i = 0; i < mplayer(side)->numgoals; ++i) {
  988.     goal = mplayer(side)->goals[i];
  989.     if (goal != NULL && goal->type == goaltype) {
  990.         return goal;
  991.     }
  992.     }
  993.     return NULL;
  994. }
  995.  
  996. /* This is for when a unit needs a plan and asks its side for one. */
  997.  
  998. void
  999. mplayer_decide_plan(side, unit)
  1000. Side *side;
  1001. Unit *unit;
  1002. {
  1003.     Plan *plan = unit->plan;
  1004.  
  1005.     if (plan == NULL || !plan->aicontrol) return;
  1006.     if (!mplayer(side)->trytowin) {
  1007.     plan->type = PLAN_RANDOM;
  1008.     clear_task_agenda(unit->plan);
  1009.     return;
  1010.     }
  1011.     switch (plan->type) {
  1012.       case PLAN_PASSIVE:
  1013.       case PLAN_NONE:
  1014.     if (mobile(unit->type)) {
  1015.         /* Maybe assign to exploration. */
  1016.         if (!g_see_all() && !g_terrain_seen() /* should be "has goal" */) {
  1017.         if (need_this_type_to_explore(side, unit->type)) {
  1018.             /* also limit to a total percentage, in case
  1019.                exploration needs are very high */
  1020.             assign_to_exploration(side, unit);
  1021.         } else {
  1022.             assign_to_offense(side, unit);
  1023.         }
  1024.         } else if (1) {
  1025.         assign_to_offense(side, unit);
  1026.         } else {
  1027. /*        assign_to_defense(side, unit); */
  1028.         }
  1029.     } else {
  1030.         if ((!g_see_all() && !g_terrain_seen())
  1031.             && need_this_type_to_build_explorers(side, unit->type)) {
  1032.         assign_to_explorer_construction(side, unit);
  1033.         } else if (type_can_build_attackers(side, unit->type)) {
  1034.             assign_to_offense_support(side, unit);
  1035.         } else {
  1036.         assign_to_defense_support(side, unit);
  1037.         }
  1038.     }
  1039.     break;
  1040.       case PLAN_OFFENSIVE:
  1041.     /* leave plan alone */
  1042.     break;
  1043.       case PLAN_EXPLORATORY:
  1044.     /* leave plan alone */
  1045.     break;
  1046.       case PLAN_DEFENSIVE:
  1047.     /* leave plan alone */
  1048.     break;
  1049.       default:
  1050.     break;
  1051.     }
  1052. }
  1053.  
  1054. int
  1055. need_this_type_to_explore(side, u)
  1056. Side *side;
  1057. int u;
  1058. {
  1059.     int s, numcontacted = 0, numfound = 0;
  1060.  
  1061.     if (!mobile(u)) return FALSE;
  1062.     for (s = 1; s <= numsides; ++s) {
  1063.         if (s == side->id) continue;
  1064.     if (mplayer(side)->contacted[s]) ++numcontacted;
  1065.     if (mplayer(side)->homefound[s]) ++numfound;
  1066.     }
  1067.     if (numcontacted == 0) {
  1068.     return TRUE;
  1069.     } else if (numfound == 0) {
  1070.     return probability(50);
  1071.     } else if (numfound < numsides - 1) {
  1072.     return probability(10);
  1073.     } else {
  1074.     return FALSE;
  1075.     }
  1076. }
  1077.  
  1078. struct weightelt {
  1079.     int weight;
  1080.     long data;
  1081. };
  1082.  
  1083. static int
  1084. compare_weights(w1, w2)
  1085. CONST void *w1, *w2;
  1086. {
  1087.     return (((struct weightelt *) w2)->weight - ((struct weightelt *) w1)->weight);
  1088. }
  1089.  
  1090. /* Set the unit up as an explorer and let it go. */
  1091.  
  1092. void
  1093. assign_to_exploration(side, unit)
  1094. Side *side;
  1095. Unit *unit;
  1096. {
  1097.     int numweights = 0, weight, i, dist;
  1098.     struct weightelt weights[MAXTHEATERS];
  1099.     Theater *theater;
  1100.  
  1101.     /* Unit's goal in life will be to see that the world is all known. */
  1102.     unit->plan->type = PLAN_EXPLORATORY;
  1103.     set_unit_theater(unit, NULL);
  1104.     /* Find the theater most in need of exploration. */
  1105.     for_all_theaters(side, theater) {
  1106.         if (theater->size > 0 && theater->unexplored > 0) {
  1107.         weight = (100 * theater->unexplored) / theater->size;
  1108.         /* Downrate theaters that are far away. */
  1109.         dist = distance(unit->x, unit->y, theater->x, theater->y)
  1110.           - isqrt(theater->size) / 2;
  1111.         if (dist < 0) dist = 0;
  1112.         weight /= max(1, (4 * dist) / area.maxdim);
  1113.         /* Flatten out 10% variations. */
  1114.         weight = 10 * (weight / 10);
  1115.         weights[numweights].weight = weight;
  1116.         weights[numweights].data = theater->id;
  1117.         ++numweights;
  1118.         }
  1119.     }
  1120.     if (numweights > 0) {
  1121.         qsort(weights, numweights, sizeof(struct weightelt), compare_weights);
  1122.         /* Choose randomly among theaters of equal weight. */
  1123.         for (i = 0; i < numweights; ++i)
  1124.       if (weights[i].weight < weights[0].weight) break;
  1125.         theater = mplayer(side)->theatertable[weights[xrandom(i)].data];
  1126.     } else {
  1127.         theater = NULL;
  1128.     }
  1129.     assign_explorer_to_theater(side, unit, theater);
  1130. }
  1131.  
  1132. int probably_explorable PROTO ((Side *side, int x, int y, int u));
  1133.  
  1134. int
  1135. probably_explorable(side, x, y, u)
  1136. Side *side;
  1137. int x, y, u;
  1138. {
  1139.     int dir, x1, y1, tview, t;
  1140.  
  1141.     for_all_directions(dir) {
  1142.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1143.             tview = terrain_view(side, x, y);
  1144.             if (tview == UNSEEN)
  1145.               return TRUE;
  1146.             t = vterrain(tview);
  1147.             if (could_move(u, t))
  1148.               return TRUE;
  1149.         }
  1150.     }
  1151.     return FALSE;
  1152. }
  1153.  
  1154. void
  1155. assign_explorer_to_theater(side, unit, theater)
  1156. Side *side;
  1157. Unit *unit;
  1158. Theater *theater;
  1159. {
  1160.     int sq, x, y, tries = 0;
  1161.     Goal *goal;
  1162.     
  1163.     if (theater != NULL) {
  1164.     set_unit_theater(unit, theater);
  1165.     ++(theater->numassigned[unit->type]);
  1166.     goal = create_goal(GOAL_VICINITY_KNOWN, side, TRUE);
  1167.     sq = isqrt(theater->size);
  1168.     while (++tries < 100) {
  1169.         /* Select a random point within the theater. */
  1170.         x = theater->xmin;  y = theater->ymin;
  1171.         x += (xrandom(theater->xmax - theater->xmin)
  1172.           + xrandom(theater->xmax - theater->xmin)) / 2;
  1173.         y += (xrandom(theater->ymax - theater->ymin)
  1174.           + xrandom(theater->ymax - theater->ymin)) / 2;
  1175.         if (theater_at(side, x, y) == theater
  1176.         && terrain_view(side, x, y) == UNSEEN
  1177.         && probably_explorable(side, x, y, unit->type))
  1178.           break;
  1179.     }
  1180.     goal->args[0] = x;  goal->args[1] = y;
  1181.     goal->args[2] = goal->args[3] = sq / 2;
  1182.     unit->plan->maingoal = goal;
  1183.     DMprintf("%s now assigned to exploration in %s, around %d,%d\n",
  1184.          unit_desig(unit), theater->name, x, y);
  1185.     }
  1186. }
  1187.  
  1188. int
  1189. need_this_type_to_build_explorers(side, u)
  1190. Side *side;
  1191. int u;
  1192. {
  1193.     int s, u2;
  1194.     
  1195.     for (s = 1; s <= numsides; ++s) {
  1196.     if (mplayer(side)->contacted[s]) return FALSE;
  1197.     if (mplayer(side)->homefound[s]) return FALSE;
  1198.     }
  1199.     for_all_unit_types(u2) {
  1200.     if (mobile(u2)
  1201.         /* should also check u2 is a useful explorer */
  1202.         && uu_acp_to_create(u, u2) > 0) return TRUE;
  1203.     }
  1204.     return FALSE;
  1205. }
  1206.  
  1207. /* Explorer constructors concentrate on building types that are good for
  1208.    exploration. */
  1209.  
  1210. void
  1211. assign_to_explorer_construction(side, unit)
  1212. Side *side;
  1213. Unit *unit;
  1214. {
  1215.     /* Unit's goal in life will be to help see that the world is all known. */
  1216.     unit->plan->type = PLAN_EXPLORATORY;
  1217.     DMprintf("%s assigned to explorer construction\n", unit_desig(unit));
  1218. }
  1219.  
  1220. void
  1221. assign_to_offense(side, unit)
  1222. Side *side;
  1223. Unit *unit;
  1224. {
  1225.     int numweights = 0, weight;
  1226.     struct weightelt weights[MAXTHEATERS];
  1227.     Goal *goal;
  1228.     Theater *homefront, *theater;
  1229.  
  1230.     unit->plan->type = PLAN_OFFENSIVE;
  1231.     clear_task_agenda(unit->plan);
  1232.     /* If our home area is being threatened, assign the unit to it. */
  1233.     if ((homefront = mplayer(side)->homefront) != NULL
  1234.         && homefront->enemystrengthmin > 0) {
  1235.     set_unit_theater(unit, homefront);
  1236.     goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
  1237.     goal->args[0] = homefront->x;  goal->args[1] = homefront->y;
  1238.     goal->args[2] = goal->args[3] = isqrt(homefront->size);
  1239.     unit->plan->maingoal = goal;
  1240.     DMprintf("%s assigned to offensive in the home front\n",
  1241.          unit_desig(unit));
  1242.     return;
  1243.     }
  1244.     /* If the theater the unit is currently in is being threatened, assign the unit to it. */
  1245.     /* (should just increase it weight in next calculation?) */
  1246.     if ((theater = theater_at(side, unit->x, unit->y)) != NULL
  1247.         && theater->enemystrengthmin > 0) {
  1248.     set_unit_theater(unit, theater);
  1249.     goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
  1250.     /* (should randomize?) */
  1251.     goal->args[0] = theater->x;  goal->args[1] = theater->y;
  1252.     goal->args[2] = (theater->xmax - theater->xmin) / 2;
  1253.     goal->args[3] = (theater->ymax - theater->ymin) / 2;
  1254.     unit->plan->maingoal = goal;
  1255.     DMprintf("%s assigned to offensive in the theater where it's at now\n",
  1256.          unit_desig(unit));
  1257.     return;
  1258.     }
  1259.     for_all_theaters(side, theater) {
  1260.         if (theater->enemystrengthmin > 0 || theater->unexplored > 0) {
  1261.         /* (should weight by strength relative to own units already there) */
  1262.         weight = theater->enemystrengthmax * 20;
  1263.         if (distance(unit->x, unit->y, theater->x, theater->y) > area.width / 2) {
  1264.         weight /= 2;
  1265.         }
  1266.         weight += (10 * theater->unexplored) / max(1, theater->size);
  1267.         weights[numweights].weight = weight;
  1268.         weights[numweights].data = theater->id;
  1269.         ++numweights;
  1270.         }
  1271.     }
  1272.     if (numweights > 0) {
  1273.         qsort(weights, numweights, sizeof(struct weightelt), compare_weights);
  1274.         theater = mplayer(side)->theatertable[weights[0].data];
  1275.     } else {
  1276.         theater = theater_at(side, unit->x, unit->y);
  1277.     }
  1278.     set_unit_theater(unit, theater);
  1279.     if (theater != NULL) {
  1280.     ++(theater->numassigned[unit->type]);
  1281.     goal = create_goal(GOAL_VICINITY_HELD, side, TRUE);
  1282.     /* (should randomize?) */
  1283.     goal->args[0] = theater->x;  goal->args[1] = theater->y;
  1284.     goal->args[2] = (theater->xmax - theater->xmin) / 2;
  1285.     goal->args[3] = (theater->ymax - theater->ymin) / 2;
  1286.     unit->plan->maingoal = goal;
  1287.     DMprintf("%s now assigned to offensive in %s",
  1288.          unit_desig(unit), theater->name);
  1289.     if (numweights > 1) {
  1290.         DMprintf(" (weight %d; runnerup was %s, weight %d)",
  1291.              weights[0].weight,
  1292.              (mplayer(side)->theatertable[weights[1].data])->name,
  1293.              weights[1].weight);
  1294.     }
  1295.     DMprintf("\n");
  1296.     } else {
  1297.     DMprintf("%s now assigned to offensive in no theater",
  1298.          unit_desig(unit));
  1299.     }
  1300. }
  1301.  
  1302. void
  1303. assign_to_offense_support(side, unit)
  1304. Side *side;
  1305. Unit *unit;
  1306. {
  1307.     unit->plan->type = PLAN_OFFENSIVE;
  1308.     clear_task_agenda(unit->plan);
  1309. }
  1310.  
  1311. int
  1312. type_can_build_attackers(side, u)
  1313. Side *side;
  1314. int u;
  1315. {
  1316.     int u2;
  1317.     
  1318.     for_all_unit_types(u2) {
  1319.     if (mobile(u2)
  1320.         && (type_can_attack(u2) || type_can_fire(u2))
  1321.         && uu_acp_to_create(u, u2) > 0) return TRUE;
  1322.     }
  1323.     return FALSE;
  1324. }
  1325.  
  1326. int
  1327. mplayer_preferred_build_type(side, unit, plantype)
  1328. Side *side;
  1329. Unit *unit;
  1330. int plantype;
  1331. {
  1332.     int u = unit->type, u2, u3, maxworth = 0;
  1333.     int prefs[MAXUTYPES];
  1334.     int t, knownterrain[MAXTTYPES], fringeterrain[MAXTTYPES], sumfringe, totfringe;
  1335.     int enemytypes[MAXUTYPES];
  1336.     int numtotransport[MAXUTYPES];
  1337.     int x, y, dir, x1, y1;
  1338.     int blockedallaround;
  1339.     int uview;
  1340.     Unit *unit2, *occ;
  1341.     Theater *theater;
  1342.  
  1343.     if (plantype == PLAN_EXPLORATORY) {
  1344.     /* Calculate the amount of each type of terrain at the edges
  1345.        of the known world. */
  1346.     for_all_terrain_types(t) knownterrain[t] = fringeterrain[t] = 0;
  1347.     for_all_interior_cells(x, y) {
  1348.         if (terrain_view(side, x, y) != UNSEEN) {
  1349.         ++(knownterrain[(int) terrain_at(x, y)]);
  1350.         for_all_directions(dir) {
  1351.             point_in_dir(x, y, dir, &x1, &y1);
  1352.             if (terrain_view(side, x1, y1) == UNSEEN) {
  1353.             ++(fringeterrain[(int) terrain_at(x, y)]);
  1354.             break;
  1355.             }
  1356.         }
  1357.         }
  1358.     }
  1359.     } else {
  1360.         for_all_unit_types(u2) enemytypes[u2] = 0;
  1361.         for_all_interior_cells(x, y) {
  1362.         if (g_see_all() || cover(side, x, y) > 0) {
  1363.         for_all_stack(x, y, unit2) {
  1364.             if (unit2->side != side) ++enemytypes[unit2->type];
  1365.             /* (should count occ types recursively also) */
  1366.             for_all_occupants(unit2, occ) {
  1367.             ++enemytypes[occ->type];
  1368.             }
  1369.         }
  1370.         } else {
  1371.         if ((uview = unit_view(side, x, y)) != EMPTY) {
  1372.             if (side_n(vside(uview)) != side) ++enemytypes[vtype(uview)];
  1373.         }
  1374.         }
  1375.         }
  1376.     }
  1377.     /* Calculate a basic preference for each possible type. */
  1378.     for_all_unit_types(u2) {
  1379.     prefs[u2] = 0;
  1380.     if (uu_acp_to_create(u, u2) > 0
  1381.         /* tmp hack until mplayer can do research */
  1382.         && (u_tech_to_build(u2) > 0 ? side->tech[u2] >= u_tech_to_build(u2) : TRUE)
  1383.         && type_allowed_on_side(u2, side)) {
  1384.         if (0 /* any demand in this unit's theater */) {
  1385.         } else if (need_more_transportation(side)) {
  1386.             for_all_unit_types(u3) {
  1387.             numtotransport[u3] = 0;
  1388.             }
  1389.             for_all_theaters(side, theater) {
  1390.             for_all_unit_types(u3) {
  1391.             numtotransport[u3] += theater->numtotransport[u3];
  1392.             }
  1393.             }
  1394.             for_all_unit_types(u3) {
  1395.             if (numtotransport[u3] > 0
  1396.             && mobile(u2)
  1397.             && could_carry(u2, u3)) {
  1398.             prefs[u2] += numtotransport[u3];
  1399.             }
  1400.             }
  1401.         } else {
  1402.         /* Prefer units by overall suitability for general plan. */
  1403.         if (plantype == PLAN_EXPLORATORY) {
  1404.             sumfringe = totfringe = 0;
  1405.             for_all_terrain_types(t) {
  1406.             totfringe += fringeterrain[t];
  1407.             if (!terrain_always_impassable(u2, t))
  1408.               sumfringe += fringeterrain[t];
  1409.             }
  1410.             if (totfringe < 1) sumfringe = totfringe = 1;
  1411.             /* Scale - so 5% diffs in amt of crossable terrain
  1412.                don't affect result. */
  1413.             prefs[u2] = (20 * sumfringe) / totfringe;
  1414.             prefs[u2] /= max(1, normal_completion_time(u, u2) / 8);
  1415.         } else {
  1416.             for_all_unit_types(u3) {
  1417.                if (enemytypes[u3] > 0) {
  1418.                    if (uu_zz_bhw(u2, u3) > 0) {
  1419.                        prefs[u2] += uu_zz_bhw(u2, u3) * enemytypes[u3];
  1420.                    }
  1421.                    if (uu_zz_bcw(u2, u3) > 0) {
  1422.                        prefs[u2] += uu_zz_bcw(u2, u3) * enemytypes[u3];
  1423.                    }
  1424.                }
  1425.             }
  1426.             prefs[u2] /= max(1, normal_completion_time(u, u2) / 8);
  1427.         }
  1428.         if (prefs[u2] < 1) prefs[u2] = 1;
  1429.         }
  1430.     } else {
  1431.     }
  1432.     }
  1433.     /* Units that can't even get out of the builder get their preference
  1434.        cut.  This helps prevent the construction of large ships in Denver. */
  1435.     /* (should allow if units would have some other way to leave) */
  1436.     if (1 /* plantype == PLAN_EXPLORATORY */) {
  1437.     for_all_unit_types(u2) {
  1438.         if (prefs[u2] > 1) {
  1439.         blockedallaround = TRUE;
  1440.         for_all_directions(dir) {
  1441.             point_in_dir(unit->x, unit->y, dir, &x1, &y1);
  1442.             if (!terrain_always_impassable(u2, terrain_at(x1, y1))) {
  1443.                 blockedallaround = FALSE;
  1444.                 break;
  1445.             }
  1446. #if 0  /* for the moment */
  1447.             if (unit_at(x1, y1) != NULL) {
  1448.                 blockedallaround = FALSE;
  1449.                 break;
  1450.             }
  1451. #endif
  1452.         }
  1453.         if (blockedallaround) prefs[u2] = 0;
  1454.         }
  1455.     }
  1456.     }
  1457.     /* Look for an existing incomplete occupant and prefer to build its type,
  1458.        if it is in the choices in the typelist. */
  1459.     for_all_occupants(unit, occ) {
  1460.     if (in_play(occ) && !completed(occ)) {
  1461.         if (prefs[occ->type] > 0 && flip_coin()) return occ->type;
  1462.     }
  1463.     }
  1464.     for_all_unit_types(u2) if (prefs[u2] < 0) prefs[u2] = 0;
  1465.     return select_by_weight(prefs, numutypes);
  1466. }
  1467.  
  1468. /* (should make this a generic routine) */
  1469.  
  1470. int
  1471. select_by_weight(arr, numvals)
  1472. int *arr, numvals;
  1473. {
  1474.     int sum = 0, i, n;
  1475.  
  1476.     sum = 0;
  1477.     for (i = 0; i < numvals; ++i) {
  1478.     sum += arr[i];
  1479.     }
  1480.     if (sum == 0) return -1;
  1481.     /* We now know the range, make a random index into it. */
  1482.     n = xrandom(sum);
  1483.     /* Go through again to figure out which choice the index refs. */
  1484.     sum = 0;
  1485.     for (i = 0; i < numvals; ++i) {
  1486.     sum += arr[i];
  1487.     if (sum >= n) {
  1488.         return i;
  1489.     }
  1490.     }
  1491.     run_error("Ooh weird");
  1492.     return 0;
  1493. }
  1494.  
  1495. int
  1496. need_more_transportation(side)
  1497. Side *side;
  1498. {
  1499.     int u3, u2, anytransport;
  1500.     Theater *theater;
  1501.  
  1502.     for_all_theaters(side, theater) {
  1503.     for_all_unit_types(u3) {
  1504.         if (theater->numtotransport[u3] > 0) {
  1505.         anytransport = FALSE;
  1506.         for_all_unit_types(u2) {
  1507.             if (theater->numassigned[u2] > 0
  1508.             && mobile(u2)
  1509.             && could_carry(u2, u3))
  1510.               anytransport = TRUE;
  1511.         }
  1512.         if (!anytransport) return TRUE;
  1513.         }
  1514.     }
  1515.     }
  1516.     return FALSE;
  1517. }
  1518.  
  1519. void
  1520. assign_to_defense_support(side, unit)
  1521. Side *side;
  1522. Unit *unit;
  1523. {
  1524.     unit->plan->type = PLAN_DEFENSIVE;
  1525.     clear_task_agenda(unit->plan);
  1526. }
  1527.  
  1528. /* This is called when an exploring unit gets confused about what to do. */
  1529.  
  1530. int
  1531. mplayer_guide_explorer(side, unit)
  1532. Side *side;
  1533. Unit *unit;
  1534. {
  1535.     if (probability(10) && build_base_for_self(side, unit))
  1536.       return TRUE;
  1537.     if (probability(10) && build_base_for_others(side, unit))
  1538.       return TRUE;
  1539.     return FALSE;
  1540. }
  1541.  
  1542. /* Decide for the unit whether it should build a base for its own benefit. */
  1543.  
  1544. int
  1545. build_base_for_self(side, unit)
  1546. Side *side;
  1547. Unit *unit;
  1548. {
  1549.     int u = unit->type, u2, cando = FALSE;
  1550.  
  1551.     for_all_unit_types(u2) {
  1552.     if (uu_acp_to_create(u, u2) > 0
  1553.         && (uu_creation_cp(u, u2) >= u_cp(u2)
  1554.             || uu_acp_to_build(u, u2) > 0)
  1555.         /* (should check if any advantage to building) */
  1556.        ) {
  1557.        cando = TRUE;
  1558.        break;
  1559.     }
  1560.     }
  1561.     if (cando) {
  1562.     DMprintf("%s building %s as a base for itself\n",
  1563.              unit_desig(unit), u_type_name(u2));
  1564.     set_construction(unit, u2, 1);
  1565.     return TRUE;
  1566.     }
  1567.     return FALSE;
  1568. }
  1569.  
  1570. /* Decide for the unit whether it should build a base to help other units. */
  1571.  
  1572. int
  1573. build_base_for_others(side, unit)
  1574. Side *side;
  1575. Unit *unit;
  1576. {
  1577.     return FALSE;
  1578. }
  1579.  
  1580. int
  1581. build_depot_for_self(side, unit)
  1582. Side *side;
  1583. Unit *unit;
  1584. {
  1585.     int u = unit->type, u2, cando = FALSE;
  1586.  
  1587.     for_all_unit_types(u2) {
  1588.     if (uu_acp_to_create(u, u2) > 0
  1589.         && (uu_creation_cp(u, u2) >= u_cp(u2)
  1590.             || uu_acp_to_build(u, u2) > 0)
  1591.         /* (should check if any advantage to building) */
  1592.        ) {
  1593.        cando = TRUE;
  1594.        break;
  1595.     }
  1596.     }
  1597.     if (cando) {
  1598.     DMprintf("%s building %s as a depot for itself\n",
  1599.              unit_desig(unit), u_type_name(u2));
  1600.     set_construction(unit, u2, 1);
  1601.     return TRUE;
  1602.     }
  1603.     return FALSE;
  1604. }
  1605.  
  1606. void
  1607. mplayer_react_to_action_result(side, unit, rslt)
  1608. Side *side;
  1609. Unit *unit;
  1610. int rslt;
  1611. {
  1612.     /* (should check on supplies) */
  1613. }
  1614.  
  1615. /* This is a hook that runs after each task is executed. */
  1616.  
  1617. void
  1618. mplayer_react_to_task_result(side, unit, task, rslt)
  1619. Side *side;
  1620. Unit *unit;
  1621. Task *task;
  1622. int rslt;
  1623. {
  1624.     Unit *occ;
  1625.     Theater *theater;
  1626.  
  1627.     /* React to an apparent blockage. */
  1628.     if (rslt == TASK_FAILED
  1629.     && task != NULL
  1630.     && task->type == TASK_MOVETO
  1631.     && task->retrynum > 2) {
  1632.     if (desired_direction_impassable(unit, task->args[0], task->args[1])) {
  1633.         if (could_be_ferried(unit, task->args[0], task->args[1])) {
  1634.         if (unit->plan->type == PLAN_EXPLORATORY && flip_coin()) {
  1635.                   /* (could also change task within the same theater) */
  1636.             DMprintf("%s blocked while exploring, changing theaters\n",
  1637.                  unit_desig(unit));
  1638.             change_to_adjacent_theater(side, unit);
  1639.         } else {
  1640.             DMprintf("%s blocked, will wait for transport\n",
  1641.                  unit_desig(unit));
  1642.             theater = theater_at(side, unit->x, unit->y);
  1643.             if (theater != NULL) {
  1644.             ++(theater->numtotransport[unit->type]);
  1645.             }
  1646.             unit->plan->reserve = TRUE;
  1647.             unit->plan->waitingfortransport = TRUE;
  1648.         }
  1649.         } else {
  1650.             if (unit->occupant) {
  1651.             DMprintf("%s blocked while transporting, will sit briefly\n",
  1652.                  unit_desig(unit));
  1653.             unit->plan->reserve = TRUE;
  1654.             for_all_occupants(unit, occ) {
  1655.                 wake_unit(occ, FALSE, -1, NULL);
  1656.             }
  1657.             return;
  1658.             }
  1659.         /* Another option is to transfer to another theater.
  1660.            This is especially useful when exploring. */
  1661.         if (unit->plan->type == PLAN_EXPLORATORY) {
  1662.             DMprintf("%s blocked while exploring, changing theaters\n",
  1663.                  unit_desig(unit));
  1664.             change_to_adjacent_theater(side, unit);
  1665.         }
  1666.         }
  1667.     } else if (blocked_by_enemy(unit, task->args[0], task->args[1])) {
  1668.         /* (should decide if allowable risk to passengers) */
  1669.         DMprintf("%s blocked by enemy\n", unit_desig(unit));
  1670.         attack_blockage(side, unit, task->args[0], task->args[1]); 
  1671.     }
  1672.     return;
  1673.     }
  1674.     /* React to inability to resupply by trying to build a base. */
  1675.     if (rslt == TASK_FAILED
  1676.     && task != NULL
  1677.     && task->type == TASK_RESUPPLY
  1678.     && task->retrynum > 2) {
  1679.         set_unit_reserve(side, unit, FALSE, FALSE);
  1680.         build_depot_for_self(side, unit);
  1681.     }
  1682. #if 0    /* I'm not sure the following is really necessary - */
  1683.     /* - if the task fails, but a good victim is to be seen nearby, then the AI will
  1684.        eventually assign a unit to attack, quite likely the one whose task just failed. */
  1685.     /* React to a target unit trying to get away; if we can still see it nearby
  1686.        somewhere, adjust to pursue. */
  1687.     if (rslt == TASK_FAILED
  1688.     && task != NULL
  1689.     && task->type == TASK_HIT_UNIT
  1690.     ) {
  1691.     int u = unit->type, tx, ty, dist, enemythere, uview, u2, s2;
  1692.     Unit *unit2, *target;
  1693.  
  1694.     tx = task->args[0];  ty = task->args[1];
  1695.     tu = task->args[2];  ts = task->args[3];
  1696.     if (can_see_actual_units(side, tx, ty)) {
  1697.         for_all_stack(tx, ty, unit2) {
  1698.                 if (unit2->side != side
  1699.             && (tu == NONUTYPE || tu == unit2->type)
  1700.             ) {
  1701.             /* A target is still there; task must have failed for some
  1702.                other reason. */
  1703.             return;
  1704.             }
  1705.         }
  1706.         /* They're gone! */
  1707.     } else {
  1708.         /* Assess old image or emptiness. */
  1709.         uview = unit_view(side, tx, ty);
  1710.         if (uview != EMPTY) {
  1711.             if (tu == NONUTYPE || tu == vtype(uview)) {
  1712.                 /* Target is still here. */
  1713.                 return;
  1714.             }
  1715.         }
  1716.         /* They're gone! */
  1717.     }
  1718.     /* If we get here, the target's location is empty. */
  1719.     return;
  1720.     }
  1721. #endif
  1722. }
  1723.  
  1724. void
  1725. change_to_adjacent_theater(side, unit)
  1726. Side *side;
  1727. Unit *unit;
  1728. {
  1729.     int dir;
  1730.     Theater *theater;
  1731.  
  1732.     if ((theater = unit_theater(unit)) != NULL) {
  1733.        for_all_directions(dir) {
  1734.            if (theater == mplayer(side)->perimeters[dir]) {
  1735.                assign_explorer_to_theater(side, unit,
  1736.                    mplayer(side)->perimeters[flip_coin() ? left_dir(dir) : right_dir(dir)]);
  1737.                break;
  1738.            }
  1739.            if (theater == mplayer(side)->midranges[dir]) {
  1740.                assign_explorer_to_theater(side, unit,
  1741.                    mplayer(side)->midranges[flip_coin() ? left_dir(dir) : right_dir(dir)]);
  1742.                break;
  1743.            }
  1744.            if (theater == mplayer(side)->remotes[dir]) {
  1745.                assign_explorer_to_theater(side, unit,
  1746.                    mplayer(side)->remotes[flip_coin() ? left_dir(dir) : right_dir(dir)]);
  1747.                break;
  1748.            }
  1749.        }
  1750.     }
  1751. }
  1752.  
  1753. /* (should account for impassability because of borders, etc) */
  1754.  
  1755. int
  1756. desired_direction_impassable(unit, x, y)
  1757. Unit *unit;
  1758. int x, y;
  1759. {
  1760.     int dirs[NUMDIRS], numdirs, i, x1, y1, t, numbaddirs = 0;
  1761.  
  1762.     numdirs = choose_move_dirs(unit, x, y, TRUE, NULL, NULL, dirs);
  1763.     for (i = 0; i < numdirs; ++i) {
  1764.     point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
  1765.     t = terrain_at(x1, y1);
  1766.     if (terrain_always_impassable(unit->type, t)) ++numbaddirs;
  1767.     }
  1768.     return (numbaddirs == numdirs);
  1769. }
  1770.  
  1771. int
  1772. could_be_ferried(unit, x, y)
  1773. Unit *unit;
  1774. int x, y;
  1775. {
  1776.     int dirs[NUMDIRS], numdirs, i, x1, y1, t, u2;
  1777.  
  1778.     if (!carryable(unit->type)) return FALSE;
  1779.     numdirs = choose_move_dirs(unit, x, y, FALSE, NULL, NULL, dirs);
  1780.     for (i = 0; i < numdirs; ++i) {
  1781.     point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
  1782.     t = terrain_at(x1, y1);
  1783.     /* See if there is a type that can carry us through via this direction. */
  1784.     for_all_unit_types(u2) {
  1785.         if (could_carry(u2, unit->type)
  1786.             && mobile(u2)
  1787.             && !terrain_always_impassable(u2, t)) {
  1788.             return TRUE;
  1789.         }
  1790.     }
  1791.     }
  1792.     return FALSE;
  1793. }
  1794.  
  1795. /* Note the recursion - should precalc this property. */
  1796.  
  1797. int
  1798. carryable(u)
  1799. int u;
  1800. {
  1801.     int u2;
  1802.     
  1803.     for_all_unit_types(u2) {
  1804.     if (could_carry(u2, u)
  1805.         && (mobile(u2) /* || carryable(u2) */ )) return TRUE;
  1806.     }
  1807.     return FALSE;
  1808. }
  1809.  
  1810. int *accelerables = NULL;
  1811.  
  1812. int
  1813. accelerable(u)
  1814. int u;
  1815. {
  1816.     int u1, u2;
  1817.  
  1818.     if (accelerables == NULL) {
  1819.     accelerables = (int *) xmalloc(numutypes * sizeof(int));
  1820.     for_all_unit_types(u1) {    
  1821.         for_all_unit_types(u2) {
  1822.         if (could_carry(u2, u1)
  1823.             && mobile(u2)) {
  1824.             if (u_acp(u2) * u_speed(u2) > u_acp(u1) * u_speed(u1)) {
  1825. #if 0
  1826.             sameterrain = TRUE;
  1827.             for_all_terrain_types(t) {
  1828.                 if (terrain_always_impassable(u2, t)
  1829.                 && !terrain_always_impassable(u1, t)) {
  1830.                 return FALSE;
  1831.                 }
  1832.             }
  1833. #endif
  1834.             accelerables[u1] = TRUE;
  1835.             break;
  1836.             }
  1837.         }
  1838.         }
  1839.     }
  1840.     }
  1841.     return accelerables[u];
  1842. }
  1843.  
  1844. int
  1845. blocked_by_enemy(unit, x, y)
  1846. Unit *unit;
  1847. int x, y;
  1848. {
  1849.     int dirs[NUMDIRS], numdirs, i, x1, y1, t, numbaddirs = 0;
  1850.     Unit *unit2;
  1851.  
  1852.     numdirs = choose_move_dirs(unit, x, y, TRUE, NULL, NULL, dirs);
  1853.     for (i = 0; i < numdirs; ++i) {
  1854.     point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
  1855.     t = terrain_at(x1, y1);
  1856.     if (terrain_always_impassable(unit->type, t)) { ++numbaddirs; continue; }
  1857.     unit2 = unit_at(x1, y1);
  1858.     if (in_play(unit2) && unit2->side != unit->side) ++numbaddirs;
  1859.     }
  1860.     return (numbaddirs == numdirs);
  1861. }
  1862.  
  1863. void
  1864. attack_blockage(side, unit, x, y)
  1865. Side *side;
  1866. Unit *unit;
  1867. int x, y;
  1868. {
  1869.     int dirs[NUMDIRS], numdirs, i, x1, y1, t;
  1870.     Unit *unit2;
  1871.  
  1872.     numdirs = choose_move_dirs(unit, x, y, TRUE, NULL, NULL, dirs);
  1873.     for (i = 0; i < numdirs; ++i) {
  1874.     point_in_dir(unit->x, unit->y, dirs[i], &x1, &y1);
  1875.     t = terrain_at(x1, y1);
  1876.     if (terrain_always_impassable(unit->type, t))
  1877.       continue;
  1878.     unit2 = unit_at(x1, y1);
  1879.     if (unit2->side != unit->side) {
  1880.         push_hit_task(unit, x1, y1);
  1881.         return;
  1882.     }
  1883.     }
  1884. }
  1885.  
  1886. /* At the end of a turn, re-evaluate the plans of some units in case
  1887.    the situation changed. */
  1888.  
  1889. void
  1890. mplayer_finish_movement(side)
  1891. Side *side;
  1892. {
  1893.     int u;
  1894.     Unit *unit;
  1895.     Theater *theater;
  1896.  
  1897.     for_all_theaters(side, theater) {
  1898.     for_all_unit_types(u) {
  1899.         if (theater->numtotransport[u] > 0) {
  1900.         /* Find a unit needing transport. */
  1901.         for_all_side_units(side, unit) {
  1902.             if (is_active(unit)
  1903.             && unit->plan
  1904.             && unit->plan->aicontrol
  1905.             && unit->plan->waitingfortransport
  1906.             && theater_at(side, unit->x, unit->y) == theater) {
  1907.             search_for_available_transport(unit);
  1908.             unit->plan->waitingfortransport = FALSE;
  1909.             }
  1910.         }
  1911.         break;
  1912.         }
  1913.     }
  1914.     }
  1915.     for_all_side_units(side, unit) {
  1916.     if (is_active(unit)
  1917.         && unit->plan
  1918.         && unit->plan->aicontrol) {
  1919.         rethink_plan(unit);
  1920.     }
  1921.     }
  1922. }
  1923.  
  1924. Unit *
  1925. search_for_available_transport(unit)
  1926. Unit *unit;
  1927. {
  1928.     int dist, closestdist = area.maxdim;
  1929.     Unit *transport, *closesttransport = NULL;
  1930.     Theater *theater = unit_theater(unit);
  1931.  
  1932.     /* (more efficient to search adjacent cells first?) */
  1933.     for_all_side_units(unit->side, transport) {
  1934.     if (is_active(transport)
  1935.         && mobile(transport->type)
  1936.         && could_carry(transport->type, unit->type)
  1937.         && transport->occupant == NULL /* (should be "has room") */
  1938.         && transport->act != NULL /* not quite correct, but to fix bug */) {
  1939.         /* Maybe this one is already coming to get somebody. */
  1940.         if (transport->plan
  1941.         && transport->plan->tasks != NULL
  1942.         && transport->plan->tasks->type == TASK_PICKUP) {
  1943.         if (transport->plan->tasks->args[0] == unit->id) return transport;
  1944.         /* Picking up somebody else - don't hijack. */
  1945.         continue;
  1946.         }
  1947.         if (transport->plan
  1948.         && transport->plan->tasks != NULL
  1949.         && transport->plan->tasks->type == TASK_MOVETO
  1950.         && transport->plan->tasks->next != NULL
  1951.         && transport->plan->tasks->next->type == TASK_PICKUP) {
  1952.         if (transport->plan->tasks->next->args[0] == unit->id) return transport;
  1953.         /* Picking up somebody else - don't hijack. */
  1954.         continue;
  1955.         }
  1956.         dist = distance(unit->x, unit->y, transport->x, transport->y);
  1957.         if (dist < closestdist || (dist == closestdist && flip_coin())) {
  1958.         closesttransport = transport;
  1959.         closestdist = dist;
  1960.         }
  1961.         /* If transport already adjacent, no need to keep looking. */
  1962.         if (closestdist <= 1) break;
  1963.     }
  1964.     }
  1965.     if (closesttransport != NULL && closesttransport->plan != NULL) {
  1966.     clear_task_agenda(closesttransport->plan);
  1967.     /* (could inherit unit's goal, but not needed) */
  1968.     closesttransport->plan->maingoal = NULL;
  1969.     push_pickup_task(closesttransport, unit);
  1970.     push_movenear_task(closesttransport, unit->x, unit->y, 1);
  1971.     /* No longer count this unit as needing transport. */
  1972.     if (theater != NULL) {
  1973.         --(theater->numtotransport[unit->type]);
  1974.         set_unit_theater(closesttransport, theater);
  1975.     }
  1976.     DMprintf("%s will be picked up by closest transport %s\n",
  1977.              unit_desig(unit), unit_desig(closesttransport));
  1978.     return closesttransport;
  1979.     }
  1980.     return NULL;
  1981. }
  1982.  
  1983. void
  1984. rethink_plan(unit)
  1985. Unit *unit;
  1986. {
  1987.     int dist, x1, y1;
  1988.     Task *toptask = unit->plan->tasks, *nexttask = NULL;
  1989.     Plan *plan = unit->plan;
  1990.     Unit *transport;
  1991.  
  1992.     if (toptask) nexttask = toptask->next;
  1993.     if (toptask != NULL
  1994.     && (toptask->type == TASK_HIT_UNIT
  1995.         || (toptask->type == TASK_MOVETO
  1996.         && nexttask != NULL
  1997.         && nexttask->type == TASK_HIT_UNIT))
  1998.         && !plan->reserve
  1999.         && !plan->asleep
  2000.         && !plan->waitingfortransport
  2001.         && (unit->transport == NULL || !mobile(unit->transport->type))
  2002.         && ((dist = distance(unit->x, unit->y,
  2003.                  toptask->args[0], toptask->args[1]))
  2004.             >= 4 * u_acp(unit->type))
  2005.         && accelerable(unit->type)
  2006.         ) {
  2007.         DMprintf("%s looking for transport to accelerate with", unit_desig(unit));
  2008.         DMprintf("\n");
  2009.         if ((transport = search_for_available_transport(unit)) != NULL) {
  2010. /*        push_sentry_task(unit, max(1, dist / max(1, u_acp(transport->type)))); */
  2011.         plan->reserve = TRUE;
  2012.         plan->waitingfortransport = FALSE;
  2013.         }
  2014.     }
  2015.     if (unit->plan->type == PLAN_OFFENSIVE
  2016.         && toptask != NULL
  2017.         && toptask->type == TASK_MOVETO
  2018.         && distance(unit->x, unit->y, toptask->args[0], toptask->args[1])
  2019.         >= min(2, u_acp(unit->type))
  2020.         && enemy_close_by(unit->side, unit, 1 /* 2 would be better? */, &x1, &y1)
  2021.         ) {
  2022.             push_hit_task(unit, x1, y1);
  2023.             DMprintf("%s sees enemy close by, will attack it\n", unit_desig(unit));
  2024.     }
  2025.     /* (should also notice fire opportunities) */
  2026. }
  2027.  
  2028. extern int victimx, victimy, victimrating;
  2029.  
  2030. int
  2031. enemy_close_by(side, unit, dist, xp, yp)
  2032. Side *side;
  2033. Unit *unit;
  2034. int dist, *xp, *yp;
  2035. {
  2036.     int x = unit->x, y = unit->y, dir, x1, y1;
  2037.  
  2038.     victimrating = -9999;
  2039.     tmpunit = unit;
  2040.     victim_here(x, y);
  2041.     for_all_directions(dir) {
  2042.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  2043.             victim_here(x, y);
  2044.         }
  2045.     }
  2046.     if (victimrating > -9999) {
  2047.         *xp = victimx;  *yp = victimy;
  2048.         return TRUE;
  2049.     } else {
  2050.         return FALSE;
  2051.     }
  2052. }
  2053.  
  2054. void
  2055. mplayer_receive_message(side, sender, str)
  2056. Side *side, *sender;
  2057. char *str;
  2058. {
  2059.     /* First detect standard messages. */
  2060.     if (strcmp(str, "Eh?") == 0) {
  2061.     /* Don't respond, otherwise we might infinitely recurse. */
  2062.     } else if (allied_side(side, sender)) {
  2063.     } else {
  2064.     /* (should) Detect insults and respond appropriately. */
  2065.     if (strstr(str, "idiot")) {
  2066.     } else {
  2067.         /* No idea what the message was, be puzzled. */
  2068.         send_message(side, add_side_to_set(sender, NOSIDES), "Eh?");
  2069.     }
  2070.     }
  2071. }
  2072.  
  2073. /* This is used by interfaces to display the theater in use at a given point. */
  2074.  
  2075. char *
  2076. mplayer_at_desig(side, x, y)
  2077. Side *side;
  2078. int x, y;
  2079. {
  2080.     Theater *theater;
  2081.  
  2082.     if (mplayer(side) == NULL)
  2083.       return "";
  2084.     theater = theater_at(side, x, y);
  2085.     return (theater ? theater->name : "<no theater>");
  2086. }
  2087.  
  2088. int
  2089. mplayer_theater_at(side, x, y)
  2090. Side *side;
  2091. int x, y;
  2092. {
  2093.     Theater *theater;
  2094.  
  2095.     if (mplayer(side) == NULL)
  2096.       return 0;
  2097.     theater = theater_at(side, x, y);
  2098.     return (theater ? theater->id : 0);
  2099. }
  2100.  
  2101. /* also have a state reader? */
  2102.  
  2103. void
  2104. mplayer_write_state(fp, side)
  2105. FILE *fp;
  2106. Side *side;
  2107. {
  2108. #if 0 /* garbages up save/restore but has no real purpose */
  2109.     Theater *theater;
  2110.     
  2111.     fprintf(fp, "\n");
  2112.     for_all_theaters(side, theater) {
  2113.     fprintf(fp, "; theater %s\n", theater->name);
  2114.     }
  2115. #endif
  2116. }
  2117.  
  2118. /* Supporting calculations for the "mplayer" AI in Xconq.  */
  2119.  
  2120. int basic_transport_worth PROTO ((int u1, int u2));
  2121. void set_uu_btw PROTO ((int u1, int u2, int v));
  2122.  
  2123. #define DICE(N,NUMDICE,SPOTS,OFFSET)  \
  2124.   (((N) >> 14 == 0 || (N) >> 14 == 3) ?  \
  2125.    (NUMDICE = 0, SPOTS = 0, OFFSET = (N)) :  \
  2126.    (NUMDICE = ((N) >> 11) & 0x07, SPOTS = ((N) >> 7) & 0x0f, OFFSET = (N) & 0x7f))
  2127.  
  2128. /* General collections of numbers used by all machine players. */
  2129.  
  2130. int base_building = FALSE;     /* can some unit build a base */
  2131.  
  2132. /* Init used by all machine players.  Precompute useful information
  2133.    relating to unit types in general, and that usually gets referenced
  2134.    in inner loops. */
  2135.  
  2136. void
  2137. mplayer_init_shared()
  2138. {
  2139.     int u, u1, u2, t, m1, numbuilders, tmp;
  2140.     
  2141.     /* Need 3 scratch layers for routefinding. */
  2142.     allocate_area_scratch(3);
  2143.  
  2144.     if (!g_see_all() && 1 /* terrain not all known */) {
  2145.         /* Compute approx percentage occurrence of each terrain type */
  2146.         /* in the area not yet seen */
  2147.         /* (not useful if fractal gen not used) */
  2148.         for_all_terrain_types(t) {
  2149.         set_t_fraction(t, ((t_alt_max(t) - t_alt_min(t)) *
  2150.                    (t_wet_max(t) - t_wet_min(t))) / 100);
  2151.         }
  2152.     }
  2153.     /* Recognize unit types that are bases */
  2154.     for_all_unit_types(u1) {
  2155.     set_u_is_base(u1, FALSE);
  2156.     tmp = FALSE;
  2157.     for_all_material_types(m1) {
  2158.         if (um_base_production(u1, m1) > 0) {
  2159.         tmp = TRUE;
  2160.         break;
  2161.         }
  2162.     }
  2163.     if (tmp) {
  2164.         for_all_unit_types(u2) {
  2165.         if ((u1 != u2) && could_carry(u1,u2)) {
  2166.             set_u_is_base(u1, TRUE);
  2167.             continue;
  2168.         }
  2169.         }
  2170.     }
  2171.     }
  2172.     /* Note that is_base_builder is set to the type of base that can */
  2173.     /* be built.  That means that unit zero can not be a base which */
  2174.     /* can be built. */
  2175.     for_all_unit_types(u1) {
  2176.     set_u_is_transport(u1, FALSE);
  2177.     set_u_is_carrier(u1, FALSE);
  2178.     set_u_is_base_builder(u1, FALSE);
  2179.     set_u_can_make(u1, FALSE);
  2180.     set_u_can_capture(u1, FALSE);
  2181.     numbuilders = 0;
  2182. /*    ave_build_time[u1] = 0;  */
  2183.     for_all_unit_types(u2) {
  2184.         if (u_is_base(u2) &&
  2185.         could_create(u1, u2) &&
  2186.         1 /* can be made quickly? */) {
  2187.         set_u_is_base_builder(u1, u2);
  2188.         base_building = TRUE;
  2189.         }
  2190.         if (u_speed(u1) > 0 && could_carry(u1, u2)) {
  2191.         set_u_is_transport(u1, TRUE);
  2192.         }
  2193.         if (could_create(u2, u1)) {
  2194.         numbuilders++;
  2195. /*        ave_build_time[u1] += uu_make(u2,u1);  */
  2196.         set_u_can_make(u2, TRUE);
  2197.         }
  2198.         if (uu_capture(u1, u2) > 0 || uu_indep_capture(u1, u2) > 0) {
  2199.         set_u_can_capture(u1, TRUE);
  2200.         }
  2201.     }
  2202. /*    if (numbuilders > 0)
  2203.       ave_build_time[u1] /= numbuilders;  */
  2204.     }
  2205.     /* a carrier is a unit that is a mobile base, but that cannot
  2206.        move a passenger anywhere the passenger could not go itself. */
  2207.     for_all_unit_types(u1) {
  2208.     if (u_is_transport(u1)) {
  2209.         set_u_is_carrier(u1, TRUE);
  2210.         for_all_unit_types(u2) {
  2211.         if (could_carry(u1, u2)) {
  2212.             for_all_terrain_types(t) {
  2213.             if (could_move(u1, t) && !could_move(u2, t))
  2214.               set_u_is_carrier(u1, FALSE);
  2215.             }
  2216.         }
  2217.         }
  2218.     }
  2219.     }
  2220.     for_all_unit_types(u) {
  2221.     set_u_bw(u, basic_worth(u));
  2222.     }
  2223.     for_all_unit_types(u) {
  2224.     for_all_unit_types(u2) {
  2225.         set_uu_bhw(u, u2, basic_hit_worth(u, u2));
  2226.         set_uu_bcw(u, u2, basic_capture_worth(u, u2));
  2227.         set_uu_btw(u, u2, basic_transport_worth(u, u2));
  2228.     }
  2229.     }
  2230.     /* Tell how things rated. */
  2231.     if (DebugM) display_assessment();
  2232. }
  2233.  
  2234. /* A crude estimate of the worth of having one type of unit. */
  2235.  
  2236. int
  2237. basic_worth(u)
  2238. int u;
  2239. {
  2240.     int worth = 0, u2, r, range;
  2241.   
  2242.     worth += u_hp(u) * 10;
  2243.     for_all_unit_types(u2) {
  2244.     if (could_create(u, u2))
  2245.       worth += (u_bw(u2) * (50)) / 1 /* uu_make(u, u2) */;
  2246.     if (could_carry(u, u2))
  2247.       worth += (1 + u_speed(u)) * uu_capacity_x(u, u2) *
  2248.         (u_is_base(u) ? 10 : 1) * u_bw(u2) / 30;
  2249.     }
  2250.     range = 12345;
  2251.     for_all_material_types(r) {
  2252.     worth += um_base_production(u, r) * (u_is_base(u) ? 4 : 1);
  2253.     if (um_consumption_per_move(u, r) > 0)
  2254.       range = min(range, um_storage_x(u, r) / max(1, um_consumption_per_move(u, r)));
  2255.     if (um_base_consumption(u, r) > 0) 
  2256.       range =
  2257.         min(range, u_speed(u) * um_storage_x(u, r) / max(1, um_base_consumption(u, r)));
  2258.     }
  2259.     worth += u_speed(u) * u_hp(u);
  2260.     worth += (range == 12345 ? area.maxdim : range)
  2261.       * u_hp(u) / max(1, 10 - u_speed(u));
  2262.     for_all_unit_types(u2) {
  2263.     worth += (worth * uu_capture(u, u2)) / 150;
  2264.     }
  2265.     worth = isqrt(worth);
  2266.     DMprintf("unit type %s worth %d \n ", u_type_name(u), worth);
  2267.     return worth;
  2268. }
  2269.  
  2270. /* A crude estimate of the worth of having a type of unit for offense. */
  2271.  
  2272. int
  2273. offensive_worth(u)
  2274. int u;
  2275. {
  2276.     int worth = 0, u2 /* ,  r, range */;
  2277.  
  2278.     if (mobile(u)) {
  2279.         for_all_unit_types(u2) {
  2280.             if (basic_hit_worth(u, u2) > 0) worth += basic_hit_worth(u, u2);
  2281.         }
  2282.     }
  2283. #if 0  
  2284.     worth += u_hp(u) * 10;
  2285.     for_all_unit_types(u2) {
  2286.     if (could_carry(u, u2))
  2287.       worth += (1 + u_speed(u)) * uu_capacity_x(u, u2) *
  2288.         (u_is_base(u) ? 10 : 1) * u_bw(u2) / 30;
  2289.     }
  2290.     worth += u_speed(u) * u_hp(u);
  2291.     worth += (range == 12345 ? area.maxdim : range)
  2292.       * u_hp(u) / max(1, 10 - u_speed(u));
  2293.     for_all_unit_types(u2) {
  2294.     worth += (worth * uu_capture(u, u2)) / 150;
  2295.     }
  2296.     worth = isqrt(worth);
  2297. #endif
  2298.     DMprintf("unit type %s worth %d \n ", u_type_name(u), worth);
  2299.     return worth;
  2300. }
  2301.  
  2302. /* A basic estimate of the payoff of one unit type attacking another type
  2303.    directly.  This is "context-free", does not account for overall goals etc. */
  2304.  
  2305. /* (should account for number of attacks possible in one turn) */
  2306.  
  2307. int
  2308. basic_hit_worth(u, e)
  2309. int u, e;
  2310. {
  2311.     int dam, numdice, numspots, offset, avgdamage, worth = 0, anti = 0;
  2312.  
  2313.     dam = uu_damage(u, e);
  2314.     DICE(dam, numdice, numspots, offset);
  2315.     avgdamage = offset + (numdice * numspots) / 2;
  2316.     if (avgdamage > u_hp(e)) avgdamage = u_hp(e);
  2317.     worth = (uu_hit(u, e) * avgdamage) / u_hp(e);
  2318.     if (1 /* strength of counterattack */) {
  2319.     dam = uu_damage(e, u);
  2320.     DICE(dam, numdice, numspots, offset);
  2321.     avgdamage = offset + (numdice * numspots) / 2;
  2322.     if (avgdamage > u_hp(u)) avgdamage = u_hp(u);
  2323.     anti = (uu_hit(e, u) * avgdamage) / u_hp(u);
  2324.     }
  2325.     return worth - (anti * 9) / 10;
  2326. }
  2327.  
  2328. /* A crude estimate of the payoff of one unit type trying to capture. */
  2329.  
  2330. int
  2331. basic_capture_worth(u, e)
  2332. int u, e;
  2333. {
  2334.     int worth1 = 0, worth2 = 0;
  2335.  
  2336.     if (uu_capture(u, e) > 0) {
  2337.     worth1 = uu_capture(u, e) * u_acp(u) /* divided by acp/attack */;
  2338.     }
  2339.     if (uu_indep_capture(u, e) > 0) {
  2340.     worth2 = uu_indep_capture(u, e) * u_acp(u) /* divided by acp/attack */;
  2341.     }
  2342.     return max(worth1, worth2);
  2343. }
  2344.  
  2345. int
  2346. basic_transport_worth(u, u2)
  2347. int u, u2;
  2348. {
  2349.     int worth = 0;
  2350.  
  2351.     if (could_carry(u, u2)) {
  2352.     worth += 1;
  2353.     }
  2354.     return worth;
  2355. }
  2356.  
  2357. /* Some notion of the unit's "strength"? */
  2358.  
  2359. int
  2360. unit_strength(u)
  2361. int u;
  2362. {
  2363.     return 1;
  2364. }
  2365.  
  2366. /* Display the results of our calculations. */
  2367.  
  2368. void
  2369. display_assessment()
  2370. {
  2371.     int t, u, u2;
  2372.  
  2373.     DMprintf("\n\nEstimated Terrain Percentages:\n");
  2374.     for_all_terrain_types(t) {
  2375.     DMprintf(" %3d%%", t_fraction(t));
  2376.     }
  2377.     DMprintf("\nUnit Attributes:\n");
  2378.     for_all_unit_types(u) {
  2379.     DMprintf(" %-3.3s : base %d, transport %d, carrier %d, worth %d\n",
  2380.            shortest_unique_name(u), u_is_base(u),
  2381.            u_is_transport(u), u_is_carrier(u), u_bw(u));
  2382.     DMprintf("    Operate between ranges %d and %d\n", operating_range_worst(u), operating_range_best(u));
  2383.     }
  2384.     DMprintf("\nUnit vs Unit Combat:\n");
  2385.     for_all_unit_types(u) {
  2386.     for_all_unit_types(u2) DMprintf("%5d", uu_zz_bhw(u, u2));
  2387.     DMprintf("\n");
  2388.     }
  2389.     DMprintf("\nUnit vs Unit Capture:\n");
  2390.     for_all_unit_types(u) {
  2391.     for_all_unit_types(u2) DMprintf(" %4d", uu_zz_bcw(u, u2));
  2392.     DMprintf("\n");
  2393.     }
  2394.     DMprintf("\nUnit vs Unit Transport:\n");
  2395.     for_all_unit_types(u) {
  2396.     for_all_unit_types(u2) DMprintf(" %4d", uu_zz_btw(u, u2));
  2397.     DMprintf("\n");
  2398.     }
  2399.     DMprintf("\n");
  2400. }
  2401.  
  2402. void
  2403. mplayer_react_to_unit_loss(side, unit)
  2404. Side *side;
  2405. Unit *unit;
  2406. {
  2407.     int x = unit->x, y = unit->y;
  2408.     Theater *th;
  2409.  
  2410.     if (!inside_area(x, y)) {
  2411.     x = unit->prevx;  y = unit->prevy;
  2412.     }
  2413.     if (!inside_area(x, y)) return;
  2414.     if (mplayer(side) && (th = theater_at(side, x, y)) != NULL) {
  2415.         ++(th->units_lost);
  2416.     }
  2417. }
  2418.  
  2419. int
  2420. is_base_for(u1, u2)
  2421. int u1, u2;
  2422. {
  2423.     return (u_speed(u1) == 0
  2424.         && (uu_capacity_x(u2, u1) > 0
  2425.         || (uu_size(u2, u1) <= u_capacity(u1))));
  2426. }
  2427.  
  2428. int
  2429. is_carrier_for(u1, u2)
  2430. int u1, u2;
  2431. {
  2432.     return (u_speed(u1) > 0
  2433.         && (uu_capacity_x(u2, u1) > 0
  2434.         || (uu_size(u2, u1) <= u_capacity(u1))));
  2435. }
  2436.  
  2437. /* Since *.def parameters don't have setters usually, we have to supply
  2438.    some here.  These are very sensitive to how the parameters are organized,
  2439.    and they don't do any checking, so you have to careful about using them. */
  2440.  
  2441. void set_u_is_base(u, n) int u, n; {  utypes[u].is_base = n;  }
  2442. void set_u_is_transport(u, n) int u, n; {  utypes[u].is_transport = n;  }
  2443. void set_u_is_carrier(u, n) int u, n; {  utypes[u].is_carrier = n;  }
  2444. void set_u_is_base_builder(u, n) int u, n; {  utypes[u].is_base_builder = n;  }
  2445. void set_u_can_make(u, n) int u, n; {  utypes[u].can_make = n;  }
  2446. void set_u_can_capture(u, n) int u, n; {  utypes[u].can_capture = n;  }
  2447. void set_u_bw(u, n) int u, n; {  utypes[u].bw = n;  }
  2448. void set_t_fraction(t, n) int t, n; {  ttypes[t].fraction = n;  }
  2449.  
  2450. int bhwtab = -1;
  2451. int bcwtab = -1;
  2452. int btwtab = -1;
  2453.  
  2454. void
  2455. set_uu_bhw(u1, u2, v)
  2456. int u1, u2, v;
  2457. {
  2458.     if (bhwtab < 0) {
  2459.     for (bhwtab = 0; tabledefns[bhwtab].name != NULL; ++bhwtab) {
  2460.         if (strcmp("zz-basic-hit-worth", tabledefns[bhwtab].name) == 0) {
  2461.         allocate_table(bhwtab, FALSE);
  2462.         break;
  2463.         }
  2464.     }
  2465.     }
  2466.     if (tabledefns[bhwtab].table == NULL)
  2467.       run_error("no bhw table allocated");
  2468.     (*(tabledefns[bhwtab].table))[numutypes * u1 + u2] = v;
  2469. }
  2470.  
  2471. void
  2472. set_uu_bcw(u1, u2, v)
  2473. int u1, u2, v;
  2474. {
  2475.     if (bcwtab < 0) {
  2476.     for (bcwtab = 0; tabledefns[bcwtab].name != NULL; ++bcwtab) {
  2477.         if (strcmp("zz-basic-capture-worth", tabledefns[bcwtab].name) == 0) {
  2478.         allocate_table(bcwtab, FALSE);
  2479.         break;
  2480.         }
  2481.     }
  2482.     }
  2483.     if (tabledefns[bcwtab].table == NULL)
  2484.       run_error("no bcw table allocated");
  2485.     (*(tabledefns[bcwtab].table))[numutypes * u1 + u2] = v;
  2486. }
  2487.  
  2488.  
  2489. void
  2490. set_uu_btw(u1, u2, v)
  2491. int u1, u2, v;
  2492. {
  2493.     if (btwtab < 0) {
  2494.     for (btwtab = 0; tabledefns[btwtab].name != NULL; ++btwtab) {
  2495.         if (strcmp("zz-basic-transport-worth", tabledefns[btwtab].name) == 0) {
  2496.         allocate_table(btwtab, FALSE);
  2497.         break;
  2498.         }
  2499.     }
  2500.     }
  2501.     if (tabledefns[btwtab].table == NULL)
  2502.       run_error("no btw table allocated");
  2503.     (*(tabledefns[btwtab].table))[numutypes * u1 + u2] = v;
  2504. }
  2505.